package com.wngbms.netty._02http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.multipart.MixedAttribute;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class HttpEchoHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        read(ctx, request);
        executorService.submit(() -> {
        });
    }

    private void read(ChannelHandlerContext ctx, FullHttpRequest request) {
        DecoderResult result = request.decoderResult();
        if (!result.isSuccess()) {
            HttpProtocolHelper.sendError(ctx, HttpResponseStatus.BAD_REQUEST);
            return;
        }

        HttpProtocolHelper.cacheHttpProtocol(ctx, request);
        Map<String, Object> echo = new HashMap<>();
        HttpMethod method = request.method();
        echo.put("request method", method.toString());
        String uri = request.uri();
        echo.put("request uri", uri);

        Map<String, Object> echoHeaders = new HashMap<>();
        HttpHeaders headers = request.headers();
        Iterator<Map.Entry<String, String>> iterator = headers.entries().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> header = iterator.next();
            echoHeaders.put(header.getKey(), header.getValue());
        }
        echo.put("request header", echoHeaders);

        Map<String, Object> uriDatas = paramsFromUri(request);
        echo.put("paramsFromUri", uriDatas);

        if (HttpMethod.POST.equals(method)) {
            Map<String, Object> postData = dataFromPost(request);
            echo.put("dataFormPost", postData);
        }

        String toJson = new Gson().toJson(echo);
        HttpProtocolHelper.sendJsonContent(ctx, toJson);
    }

    private Map<String, Object> dataFromPost(FullHttpRequest request) {
        Map<String, Object> postData = null;

        String contentType = request.headers().get("Content-Type");
        if (contentType == null || contentType.length() == 0) {
            postData = new HashMap<>();
            return postData;
        } else {
            contentType = contentType.trim();
        }
        if (contentType.contains("application/x-www-form-urlencoded")) {
            postData = formBodyDecode(request);
        } else if (contentType.contains("multipart/form-data")) {
            postData = formBodyDecode(request);
        } else if (contentType.contains("application/json")) {
            postData = jsonBodyDecode(request);
        } else if (contentType.contains("text/plain")) {
            ByteBuf content = request.content();
            byte[] reqContent = new byte[content.readableBytes()];
            content.readBytes(reqContent);
            String text = new String(reqContent, StandardCharsets.UTF_8);
            postData = new HashMap<>();
            postData.put("text", text);
        }
        return postData;
    }

    private Map<String, Object> jsonBodyDecode(FullHttpRequest request) {
        Map<String, Object> params = new HashMap<>();
        ByteBuf content = request.content();
        byte[] reqContent = new byte[content.readableBytes()];
        content.readBytes(reqContent);

        String strContent = new String(reqContent, StandardCharsets.UTF_8);
        JSONObject jsonObject = JSONObject.parseObject(strContent);
        for (String key : jsonObject.keySet()) {
            params.put(key, jsonObject.get(key));
        }
        return params;
    }

    private Map<String, Object> formBodyDecode(FullHttpRequest request) {
        Map<String, Object> params = new HashMap<>();

        try {
            HttpPostRequestDecoder decoder =
                    new HttpPostRequestDecoder(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE),
                            request, StandardCharsets.UTF_8);
            List<InterfaceHttpData> postData = decoder.getBodyHttpDatas();
            if (postData == null || postData.isEmpty()) {
                decoder = new HttpPostRequestDecoder(request);
                if (request.content().isReadable()) {
                    String json = request.content().toString(StandardCharsets.UTF_8);
                    params.put("body", json);
                }
            } else {
                for (InterfaceHttpData data : postData) {
                    if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
                        MixedAttribute attribute = (MixedAttribute) data;
                        params.put(attribute.getName(), attribute.getValue());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return params;
    }

    private Map<String, Object> paramsFromUri(FullHttpRequest request) {
        Map<String, Object> param = new HashMap<>();

        QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
        Map<String, List<String>> parameters = decoder.parameters();
        Set<Map.Entry<String, List<String>>> entries = parameters.entrySet();

        for (Map.Entry<String, List<String>> entry : entries) {
            param.put(entry.getKey(), entry.getValue());
        }
        return param;
    }
}
